# -*- coding: utf-8 -*-
# 练习python 方法
# 在python中调用方法， 如果传入参数数量不对，会出现typeError,并且同时会做明显的提示

import math

num = 123
print hex(num)


# 函数定义 根据传入的参数判断一个学生成绩的等级,python中参数不像java一样有类型定义，所以这有可能会导致我们传入的参数错误
# 不过我们可以在方法内部做参数校验，同时给出明确的提示
# 可以使用isinstance(x, tuple)做类型校验
# 可以使用 raise 做错误提示，这个有点像java里边的异常抛出 throw
def my_score(score):
    if not isinstance(score, (int, float)):
        raise TypeError('传入参数类型错误')
    if score < 60:
        return 'D'
    elif score >= 60 & score < 80:
        return 'C'
    elif score >= 80 & score < 90:
        return 'B'
    else:
        return 'A'


print my_score(90)


# C
# print my_score('90')
# TypeError: 传入参数类型错误

# 定义一个空函数， 什么都不做，也可以说该函数是一个占位符
def function_pass(params):
    pass


# 在java中一个方法只能放回一个值，虽说这个值可以是简单类型，对象，数字，集合，但是还是没有python中这么灵活，可以直接返回多个值
# 定义一个函数，要求计算 ax2 + bx + c = 0 这个一元二次方程的两个解
def quadratic(a, b, c):
    if not isinstance(a, (int, float)) or a == 0:
        raise TypeError('参数 a 必须是数字类型，并且不能为0')
    for param in (b, c):
        if not isinstance(param, (int, float)):
            raise TypeError('参数b, c 必须是数字类型')
    x1 = -b + math.sqrt(math.pow(b, 2) - 4 * a * c) / (2 * a)
    x2 = -b - math.sqrt(math.pow(b, 2) - 4 * a * c) / (2 * a)

    return x1, x2


print quadratic(4, 0, -4)


# 在python中可以提供默认参数， 但是需要注意的是， 必选参数必须在默认参数前边
# 如：计算x的n次方, 这个方法要求给出两个参数，x，n，其中x是必选参数，n则是默认参数， 当调用该函数是，如果没有提供n，则方法会
# 默认n为2
def power(x, n=2):
    return math.pow(x, n)


# 在java中可以存在可变参数， 同样在python中也存在这样的参数，当我们不确定需要传入的参数的数量是，
# 这个时候定义可变参数是非常有用的但是定义可变参数后 如果想将list或tuple中的元素传入到方法中，
# 该如何是好，python也考虑到这样的情况了，通过在list或者tuple变量前加*
def get_len(*nums):
    len = 0
    for x in nums:
        len += 1
    return len


# 这个地方将一个list转换为可变参数传入到方法中， 让后统计传入参数的数量
print get_len(*[1, 3, 3])


# python中不但有可变参数，还有关键字参数，这类参数使用key-value的方式将参数传入方法
# 如果需要将一个dict当着关键字参数传入到方法中，可以在dict变量前边加入**
def show_student(name, age, **info):
    print name, age, info


print show_student('mjlf', 20)
print show_student('whf', 18, sex='beautiful')
print show_student('whf', 30, **{'se': 'gire'})


# 对于关键字参数， 我们并不知道方法调用者会传入什么参数进来，这样需要我们自行判断，所以提供了命名关键字参数这个东西
# 如果在方法中出现了可变参数，那么命名关键字参数就不需要使用*做分割了
# 需要注意的是， 在python2.7中，并没有听过命名关键字这种东西
# def show_person(name, age, *, sex, address):
#     print name, age, sex, age
#
#
# print show_person('1', 20, sex='girl', address='12')

# 虽说在python2.7中没有提供命名关键字参数这种东西，但是还是有组合参数这个东西
# 组合参数就是将可变参数和关键字参数结合起来，一起放到方法中

def person(name, age, sex=0, *email, **score):
    print name, age, sex
    for em in email:
        print em
    print score


# 递归方法,计算1*2*3*4*...*n
def n_to_n(n):
    if n == 1:
        return 1
    return n * n_to_n(n - 1)


print n_to_n(10)
